#ifndef CURRENTBELTCONTAINER_H
#define CURRENTBELTCONTAINER_H

#pragma once

#include "../../ToolkitLayer.h"
#include "BeltContainerStrategy.h"
#include <IBuffer/IBuffer.h>


/**
 * This strategy extends the BeltContainerStrategy by providing active buffers
 * that control the scale and orientation of the children components, while
 * moving them along the inside region of the container.
 *
 * This is based on the InterfaceCurrentCompositeGL class in the original
 * implementation of the Tabletop Framework done by T. Isenberg and A. Miede in
 * the Interactions Lab at the University of Calgary, Canada.
 *
 * @author Fabricio Anastacio - fabriciocfa@yahoo.com
 * @since August 24, 2007
 */
class TOOLKITLAYER_API CurrentBeltContainerStrategy : public BeltContainerStrategy
{
	// Attributes
protected:
	/** The scale factor applied to the inner width of the belt before writing it to the buffer. */
	float sizeScale;
	/** The speed factor used to scale the vectors in the direction buffer. */
	float speed;
	/** The speed factor used when a component is moved in the current. */
	float moveInSpeed;
	/** Indicates if the direction and speed of the current flow is being changed. */
	bool changingFlow;
	/** The initial cursor position for the flow change in the x-coordinate. */
	float flowInitialX;
	/** The initial cursor position for the flow change in the y-coordinate. */
	float flowInitialY;
	/** The orientation (up-vector) at the point where the flow is being changed. */
	float flowOrientation[2];
	/** The minimum drag distance to have flow change. */
	float minFlowChangeDistance;
	/** The maximum drag distance allowed for flow change. */
	float maxFlowChangeDistance;

	/** Absolute size buffer type identifier. */
	unsigned int sizeBufferType;
	/** Orientation buffer type identifier. */
	unsigned int orientationBufferType;
	/** Direction buffer type identifier. */
	unsigned int directionBufferType;

	
	// Methods
public:
	/**
	 * Constructs a current belt container strategy.
	 *
	 * @param bWidth the width of the inside region (belt) of the container.
	 */
	CurrentBeltContainerStrategy(float bWidth = 100);
	/**
	 * Destroys this strategy.
	 */
	~CurrentBeltContainerStrategy(void);


	// ACCESSOR METHODS
	/**
	 * Returns the minimum drag distance to have flow change.
	 *
	 * @return the minimum drag distance to have flow change.
	 */
	inline float getMinFlowChangeDistance() { return minFlowChangeDistance; };
	/**
	 * Sets the minimum drag distance to have flow change.
	 *
	 * @param d the minimum drag distance to have flow change.
	 */
	inline void setMinFlowChangeDistance(float d) { minFlowChangeDistance = d; };
	/**
	 * Returns the maximum drag distance allowed for flow change.
	 *
	 * @return the maximum drag distance allowed for flow change.
	 */
	inline float getMaxFlowChangeDistance() { return maxFlowChangeDistance; };
	/**
	 * Sets the maximum drag distance allowed for flow change.
	 *
	 * @param d the maximum drag distance allowed for flow change.
	 */
	inline void setMaxFlowChangeDistance(float d) { maxFlowChangeDistance = d; };


protected:
	/**
	 * Initializes the properties (i. e., i-buffers) of the associated
	 * component.
	 */
	void initProperties();
	/**
	 * Handles the given event.
	 *
	 * @param evt the event to be handled.
	 */
	void onEvent(LargeDisplayEvent* evt);
	/**
	 * Defines the strategy to be used when the associated component is
	 * resized.
	 *
	 * @param width the new width of the component.
	 * @param height the new height of the component.
	 */
	void resize(unsigned int width, unsigned int height);


	/**
	 * Fills the size buffer with the scaled value of the distance between the
	 * outer and inner bounds of the container.
	 *
	 * @param buffer the buffer to be filled.
	 */
	void fillSizeBuffer(IBuffer<float>* buffer);
	/**
	 * Fills the orientation buffer with the scaled value of the distance
	 * between the outer and inner bounds of the container.
	 *
	 * @param buffer the buffer to be filled.
	 */
	void fillOrientationBuffer(IBuffer<float>* buffer);
	/**
	 * Fills the direction buffer with the scaled value of the distance between
	 * the outer and inner bounds of the container.
	 *
	 * @param buffer the buffer to be filled.
	 */
	void fillDirectionBuffer(IBuffer<float>* buffer);
	/**
	 * Updates the specified buffer by resizing (optionally) and refilling it.
	 *
	 * @param bufferType the identifier of the buffer being updated.
	 * @param resizeIt if true the buffer is resized before being updated.
	 */
	void updateBuffer(unsigned int bufferType, bool resizeIt);
};

#endif // CURRENTBELTCONTAINER_H
